/*
 * kernel/interrupt.S
 *
 * last modified by ChenJie at 2007.07.15
 *
 */

#include <asm/asmdef.h>
#include <asm/i386.h>

// 系统调用的个数:
#define nr_system_calls	((syscall_table_size)/4)

.text
ENTRY(unknown_interrupt)	//处理未识别的中断
	pushl	$do_unknown_int
	jmp	no_error_code

// int 0
ENTRY(divide_error)
	pushl	$do_divide_error
	jmp	no_error_code

// int 1
ENTRY(debug)
	pushl	$do_debug
	jmp	no_error_code

// int 2
ENTRY(nmi)
	pushl	$do_nmi
	jmp	no_error_code

// int 3
ENTRY(breakpoint)
	pushl	$do_breakpoint
	jmp	no_error_code

// int 4
ENTRY(overflow)
	pushl	$do_overflow
	jmp	no_error_code

// int 5
ENTRY(bounds_check)
	pushl	$do_bounds_check
	jmp	no_error_code

// int 6
ENTRY(invalid_opcode)
	pushl	$do_invalid_opcode
	jmp	no_error_code

// int 7
ENTRY(device_not_available)
	pushl	$do_device_not_available
	jmp	no_error_code

// int 8
ENTRY(double_fault)
	pushl	$do_double_fault
	jmp	error_code

// int 9
ENTRY(coprocessor_segment_overrun)
	pushl	$do_coprocessor_segment_overrun
	jmp	no_error_code

// int 10
ENTRY(invalid_tss)
	pushl	$do_invalid_tss
	jmp	error_code

// int 11
ENTRY(segment_not_present)
	pushl	$do_segment_not_present
	jmp	error_code

// int 12
ENTRY(stack_segment)
	pushl	$do_stack_segment
	jmp	error_code

// int 13
ENTRY(general_protection)
	pushl	$do_general_protection
	jmp	error_code

// int 14
ENTRY(page_fault)
	pushl	$do_page_fault
	jmp	no_error_code

// int 15
ENTRY(reserved)
	pushl	$do_reserved
	jmp	no_error_code

// int 16
ENTRY(coprocessor_error)
	pushl	$do_coprocessor_error
	jmp	no_error_code

no_error_code:
	xchgl	%eax, (%esp)	// do_func <---> eax
	pushl	%ebx
	pushl	%ecx
	pushl	%edx
	pushl	%edi
	pushl	%esi
	pushl	%ebp
	push	%ds
	push	%es
	push	%fs
	push	%gs
	pushl	$0		// 把0当作错误号入栈
	lea	48(%esp), %edx	//取原返回地址处堆栈指针位置，并入栈
	pushl	%edx
	movw	$KERNEL_DS, %dx
	movw	%dx, %ds
	movw	%dx, %es
	movw	%dx, %fs
	call	* %eax	//为什么有*号呢?
	addl	$8, %esp
	pop	%gs
	pop	%fs
	pop	%es
	pop	%ds
	popl	%ebp
	popl	%esi
	popl	%edi
	popl	%edx
	popl	%ecx
	popl	%ebx
	popl	%eax
	iret

error_code:
	xchgl	%eax, 4(%esp)	//此时error code <---> eax
	xchgl	%ebx, (%esp)	// do_func <---> ebx
	pushl	%ecx
	pushl	%edx
	pushl	%edi
	pushl	%esi
	pushl	%ebp
	push	%ds
	push	%es
	push	%fs
	push	%gs
	pushl	%eax		// error code -->stack
	lea	48(%esp), %eax	// 程序返回地址处堆栈指针位置入栈
	pushl	%eax
	movw	$KERNEL_DS, %ax
	movw	%ax, %ds
	movw	%ax, %es
	movw 	%ax, %fs
	call	* %ebx
	addl	$8, %esp
	pop	%gs
	pop	%fs
	pop	%es
	pop	%ds
	popl	%ebp
	popl	%esi
	popl	%edi
	popl	%edx
	popl	%ecx
	popl	%ebx
	popl	%eax
	iret


// int 32 ,0x20
ENTRY(clock_interrupt) 
	SAVE_REGS();
//对jiffies计数：
	incl	jiffies
//送发EOI,结束该硬件中断：
	movb	$0x20, %al
	outb	%al, $0x20 //OCW2, 表示中断结束
//调用do_clock_interrupt(int cpl)函数：
	movl	CS(%ebp), %eax
	andl	$0x03, %eax	//取任务的CPL,入栈
	pushl	%eax
	call	do_clock_interrupt
	addl	$4, %esp
//中断返回
	RESTORE_REGS();
	LEAVE();

// int 128, 0x80, 系统调用入口函数
ENTRY(system_call)		
	SAVE_REGS()
	popl	%eax
	cmpl	$nr_system_calls-1, %eax	# 调用号超出范围, 则返回-1
	ja	1f
	call	*sys_call_table(, %eax, 4)	# 调用相关函数
	pushl	%eax
	//此处开始处理是否进行进程调度
	call	check_schedule
	//此处进行有关的信号处理
	call	check_signal

	jmp	2f

1:	movl	$-1, %eax
	pushl	%eax
2:	RESTORE_REGS()
	LEAVE()


.data
ENTRY(sys_call_table)
#include "syscall_table.S"
syscall_table_size = (. - sys_call_table)
